<template>
    <view class="azm-chart-column-components" v-if="canvasId">
        <view class="h100 w100 chart-box" :class="{'hide-canvas':isHideCanvas && shareImg}"
              :style="canvasStyle">
            <image @tap.stop="handleTapImage" class="azm-chart-img" v-if="isHideCanvas && shareImg"
                   :src="shareImg" mode="widthFix"></image>
            <!--#ifdef MP-ALIPAY -->
            <canvas :canvas-id="canvasId" id="canvasColumn" class="charts" :style="canvasStyle"
                    :disable-scroll="disableScroll"
                    :style="{'width':cWidth*pixelRatio+'px','height':cHeight*pixelRatio+'px', 'transform': 'scale('+(1/pixelRatio)+')','margin-left':-cWidth*(pixelRatio-1)/2+'px','margin-top':-cHeight*(pixelRatio-1)/2+'px'}"></canvas>
            <!--#endif-->
            <!--#ifndef MP-ALIPAY -->
            <canvas :canvas-id="canvasId" id="canvasColumn" class="charts" :style="canvasStyle"
                    :disable-scroll="disableScroll"></canvas>
            <!--#endif-->
        </view>
    </view>
</template>

<script>
    import uCharts from '@js/u-charts/u-charts.js';

    const CHARTS_OPTS = {
        // width: uni.upx2px(750),
        // height: uni.upx2px(500),
        // 画布填充边距，顺序为上右下左，同css，但必须4位
        padding: [uni.upx2px(30), uni.upx2px(30), uni.upx2px(4), uni.upx2px(30)],
        type: "column",// 图表类型，可选值为pie、line、column、area、ring、radar、arcbar、gauge、candle、bar、mix、rose、word
        pixelRatio: 1, // 像素比，默认为1，仅支付宝小程序需要大于1，其他平台必须为1
        rotate: false, // 横屏模式，默认为false
        // 锁定横屏模式，如果在支付宝和百度小程序中使用横屏模式，请赋值true，否则每次都会旋转90度。跨端使用通过uni-app的条件编译来赋值
        rotateLock: false,
        fontSize: uni.upx2px(23), // 全局默认字体大小（可选，单位为px，默认13px）高分屏不必乘像素比，自动根据pixelRatio计算
        background: "#fff", // canvas背景颜色（如果页面背景颜色不是白色请设置为页面的背景颜色，默认#ffffff）
        // 是否开启图表可拖拽滚动 默认false 支持line, area, column, candle图表类型(需配合绑定@touchstart, @touchmove, @touchend方法)
        enableScroll: false,
        enableMarkLine: false,// 是否显示辅助线 默认false 支持line, area, column, candle, mix图表类型
        animation: true,// 是否动画展示
        duration: 800,// 动画展示时长单位毫秒
        dataLabel: true,// 是否在图表中显示数据标签内容值
        dataPointShape: true,// 是否在图表中显示数据点图形标识
        dataPointShapeType: "solid",// 数据点图形标识类型 可选值：实心solid、空心hollow
        disablePieStroke: false // 不绘制饼图（圆环图）各区块的白色分割线已迁移至扩展配置中(此配置v1.8.2前有效)
    }

    const XAXIS_OPTS = {
        // X轴刻度（数值）标签是否旋转（仅在文案超过单屏宽度时有效）
        rotateLabel: false,
        // X轴可见区域数据数量（即X轴数据密度），配合拖拽滚动使用（即仅在启用enableScroll时有效）
        itemCount: 5,
        labelCount: null,                                      // X轴可见区域标签数量（即X轴数刻度标签单屏幕限制显示的数量）
        scrollShow: false,                                  // 是否显示滚动条，配合拖拽滚动使用（即仅在启用enableScroll时有效）
        scrollAlign: "left",                                // 滚动条初始位置，left为数据整体左对齐，right为右对齐
        scrollBackgroundColor: "#EFEBEF",                   // X轴滚动条背景颜色，配合拖拽滚动使用（即仅在启用enableScroll时有效）
        scrollColor: "#A6A6A6",                             // X轴滚动条颜色，配合拖拽滚动使用（即仅在启用enableScroll时有效）
        disabled: false,                                    // 是否不绘制X轴
        calibration: false,                                 // 坐标轴刻度线是否显示 注v1.9.0有效
        disableGrid: true,                                 // 是否不绘制X轴网格(即默认绘制网格)
        gridColor: "#F7F7F7",                               // X轴网格颜色 例如#F7F7F7
        gridType: "solid",                                  // X轴网格线型 'solid'为实线、'dash'为虚线`
        gridEval: 1,                                        // X轴网格线显示间隔，即假设为2时，是隔一个刻度显示间隔
        dashLength: 4,                                      // X轴网格为虚线时，单段虚线长度
        fontColor: "#313131",                               // X轴数据点颜色 例如#313131
        fontSize: 10,                                       // X轴数据标签字体大小
        boundaryGap: "center",                              // 折线图、区域图起画点结束点方法：center为单元格中间起画，justify为0点起画即两端对齐
        axisLine: true,                                     // 坐标轴轴线是否显示 注v1.9.0有效
        axisLineColor: "#E6E6E6",                           // 坐标轴轴线颜色 注v1.9.0有效
    };

    const YAXIS_DATA_OPTS = {
        position: 'left',                                   // Y轴位置，可选值左侧left右侧right
        disabled: false,                                    // 是否不绘制Y轴
        min: 0,                                             // Y轴起始值
        max: 100,                                           // Y轴终止值
        title: "",                                          // Y轴标题
        titleFontSize: CHARTS_OPTS.fontSize,                // Y轴标题字体大小
        titleFontColor: "#313131",                          // Y轴标题字体颜色
        fontColor: "#949494",                               // Y轴数据点颜色
        fontSize: 9,                                        // Y轴数据标签字体大小
        axisLine: true,                                    // 坐标轴轴线是否显示
        calibration: false,                                 // 坐标轴刻度线是否显示
        axisLineColor: "#E9E9E9",                           // 坐标轴轴线颜色
    }

    const YAXIS_OPTS = {
        padding: 10,                                        // 多个Y轴间的间距
        showTitle: false,                                   // 是否不绘制Y轴标题
        disabled: false,                                   // 是否不绘制Y轴
        disableGrid: false,                                 // 是否不绘制Y轴网格(即默认绘制网格)
        splitNumber: 5,                                     // Y轴网格数量
        gridType: "solid",                                  // Y轴网格线型 'solid'为实线、'dash'为虚线
        dashLength: 4,                                      // Y轴网格为虚线时，单段虚线长度
        gridColor: "#F7F7F7",                               // Y轴网格颜色
    };

    const SERIES_OPTS = {
        color: "#10CA5C",
        textColor: "#313131",
        textSize: 13
    }

    /**
     * 扩展配置 （设置默认）
     * @type {{column: {"meter.border": number, "meter.fillColor": string, width: number, type: string}, pie: {border: boolean, borderColor: string, activeRadius: number, borderWidth: number, offsetAngle: number, labelWringWidth: number, labelWidth: number, activeOpacity: number}}}
     */
    const EXTRA_OBJ = {
        column: {
            width: 20,// 柱状图每项的图形宽度，单位为px
            type: "group", // 柱状图类型：group分组柱状图，stack为堆叠柱状图（未完成开发中），meter为温度计式图
            // 温度计式图配置项
            "meter.border": 1, // 边框宽度，单位为px，默认1px
            "meter.fillColor": "#FFFFFF", // 空余填充颜色
        },
        pie: { // 饼图圆环图
            activeOpacity: 0.5, // 启用Tooltip点击时，突出部分的透明度，默认0.5
            activeRadius: 10, // 启用Tooltip点击时，突出部分的宽度（最大值不得超过labelWidth），默认10
            offsetAngle: 0, // 起始角度偏移度数，顺时针方向，起点为3点钟位置（比如要设置起点为12点钟位置，即逆时针偏移90度，传入-90即可）
            labelWidth: 20, // 数据标签到饼图外圆连线的长度，单位为px
            labelWringWidth: 0, // ringChart圆环宽度，单位为px
            border: true, // 是否绘制分割线（v1.8.2有效）
            borderWidth: 2, // 分割线宽度，单位为px（v1.8.2有效）
            borderColor: "#FFFFFF", // 分割线颜色（v1.8.2有效）
        },
        line: {
            type: "curve", // 可选值：curve曲线，straight直线
            width: 3, // 折线宽度
        }
    }

    const TITLE_OPTS = { // 适用于ring、arcbar、gauge
        title: {
            name: "", // 标题内容
            fontSize: 13, // 标题字体大小（可选，单位为px）
            color: null, // 标题颜色（可选）
            offsetX: 0, // 标题横向位置偏移量，单位px，默认0
            offsetY: 0, // 标题纵向位置偏移量，单位px，默认0
        },
        subtitle: {
            name: "", // 副标题内容
            fontSize: null, // 副标题字体大小（可选，单位为px）
            color: null, // 副标题颜色（可选）
            offsetX: 0, // 副标题横向位置偏移量，单位px，默认0
            offsetY: 0, // 副标题纵向位置偏移量，单位px，默认0
        }
    }

    /**
     * 默认图裂设置
     * @type {{padding: number, itemGap: number, margin: number, backgroundColor: string, show: boolean, format: null, float: string, borderWidth: number, fontSize: number, lineHeight: number, position: string, fontColor: string, hiddenColor: string}}
     */
    const LEGEND_OPTS = {
        show: false,                                     // 是否显示各类别的图例标识
        position: "bottom",                             // 图例相对画布的显示位置，可选值：上top、右right、下bottom 、左left
        float: "center",                                // 图例位置对齐方向，上下布局时可选值：左left、中center、右right；左右布局时可选值：上top、中center、下bottom
        padding: 5,                                     // 图例内填充边距，单位px，默认5
        margin: 5,                                      // 图例外侧填充边距（仅在上下方向有效），单位px，默认5。如果图例位置为left或right时，设置此参数相当于间接控制每列图例的数量
        fontSize: 12,                                   // 字体大小，单位px。支付宝小程序需乘pixelRatio，其他平台不用
        lineHeight: 17,                                 // 字体行高。左右模式建议设置为2倍fontSize大小（避免点击事件时太近不好区分）
        backgroundColor: "rgba(0,0,0,0)",               // 图例背景颜色，默认透明。请传rgba(0,0,0,0)格式颜色
        borderWidth: 0,                                 // 图例边框线宽，单位px，默认为0
        itemGap: 10,                                    // 各个item之间的间隔，单位px，默认为10，横向布局时为水平间隔，纵向布局时为纵向间隔
        fontColor: "#313131",                              // 字体颜色，请用16进制颜色
        format: null,                                   // 【未来预留，暂未生效】自定义显示数据内容
        hiddenColor: "#CECECE",                         // 点击隐藏时，图例标识及标识文案的颜色
    }

    let Timer = null;

    export default {
        name: "tl-charts",
        components: {},
        props: {
            canvasId: {
                type: String,
                default () {
                    return `chart-column-${Date.now()}`
                }
            },
            opts: {
                type: Object,
                default () {
                    return {}
                }
            },
            type: String,
            seriesOpts: {
                type: Object,
                default () {
                    return {}
                }
            },
            legend: {
                type: [Object, Boolean],
                default () {
                    return {}
                }
            },
            yAxisTitle: {
                type: String,
                default: "次数"
            },
            xAxisTitle: {
                type: String,
                default: "次数"
            },
            xAxis: {
                type: Object,
                default () {
                    return {}
                }
            },
            yAxis: {
                type: Object,
                default () {
                    return {}
                }
            },
            extra: {
                type: Object,
                default () {
                    return {}
                }
            },
            isShowChart: {
                type: Boolean,
                default: true
            },
            // 数据列表
            dataList: {
                type: [Array, Object],
                default: () => []
            },
            isHideCanvas: {
                type: Boolean,
                default: false
            },
            disableScroll: {
                type: Boolean,
                default: false
            },
            isSingleTable: {
                type: Boolean,
                default: true
            }
        },
        data () {
            return {
                canvasStyle: "",
                pixelRatio: 1,
                cWidth: '',
                cHeight: '',
                maxSeries: 100,
                shareImg: ''
            }
        },
        created () {
            const _self = this;
            _self.$nextTick(function () {
                _self.showChart();
            })
        },
        watch: {
            dataList: {
                handler (n) {
                    this.updateData(n)
                },
                deep: true
            }
        },
        methods: {
            /**
             * 获取其他配置
             **/
            getOpts () {
                const SelectorQuery = uni.createSelectorQuery();
                SelectorQuery.in(this);
                const _self = this;
                const opts = this.opts;
                if (this.type) opts.type = this.type;
                const result = {
                    ...CHARTS_OPTS,
                    ...opts,
                }
                opts.legend = false;

                if (typeof _self.legend === "boolean") {
                    opts.legend = {
                        ...LEGEND_OPTS,
                        show: _self.legend
                    }
                } else {
                    opts.legend = {
                        ...LEGEND_OPTS,
                        ..._self.legend
                    }
                }
                // 饼图 圆环 玫瑰图
                if (["pie", "ring", "rose"].indexOf(this.type) > -1) {
                    if (!opts.lableWidth) opts.lableWidth = 15;
                }
                if (!opts.width || !opts.height) {
                    return new Promise((resolve, reject) => {
                        const NodesRef = SelectorQuery.select('.azm-chart-column-components').boundingClientRect()
                        _self.$nextTick(function () {
                            NodesRef.exec(function ([a]) {
                                // console.log(a, '+++++++++NodesRef+++++++++');
                                if (!a) return reject();
                                _self.cWidth = a.width;
                                _self.cHeight = a.height;
                                resolve({...opts, ...result, width: a.width, height: a.height})
                            })
                        })
                    })
                } else {
                    _self.cWidth = opts.width;
                    _self.cHeight = opts.height;
                }
                return Promise.resolve({...opts, ...result});
            },
            /**
             * 设置扩展配置
             * @param opts
             */
            setExtra (opts) {
                const {isEmpty, isEmptyObject} = this.$util.jude
                const extra = isEmptyObject(this.extra) ? {} : this.extra;
                for (let k in EXTRA_OBJ) {
                    if (isEmpty(extra[k])) extra[k] = {...EXTRA_OBJ[k]}
                }
                opts.extra = extra;
            },
            // 设置坐标配置
            setAxis (opts) {
                const {number_format} = this.$util;
                let _self = this;
                opts.xAxis = {
                    ...XAXIS_OPTS,
                    ..._self.xAxis,
                };

                opts.yAxis = {
                    ...YAXIS_OPTS,
                    ..._self.yAxis
                };
                if (!Array.isArray(opts.yAxis.data) || opts.yAxis.data.length === 0)
                    opts.yAxis.data = [{...YAXIS_DATA_OPTS}]
                opts.yAxis.data = opts.yAxis.data.map(value => {
                    return {
                        ...YAXIS_DATA_OPTS,
                        axisLine: _self.yAxis.axisLine === false ? false : value.axisLine,
                        max: _self.maxSeries,
                        format: function (item) {
                            if (_self.maxSeries === item) {
                                return _self.yAxisTitle
                            } else {
                                return parseFloat(number_format(item))
                            }
                        }
                    }
                })
            },

            /**
             * 获取柱状图数据
             * @returns {{series: [], categories: []}}
             */
            async getColumnData () {
                const _self = this;
                const {isEmpty, isEmptyObject} = this.$util.jude;
                //下面这个根据需要保存后台数据，我是为了模拟更新柱状图，所以存下来了
                let Column = {categories: [], series: []};
                let seriesNumArr = [];
                if (this.isSingleTable === true) {
                    let seriesData = {
                        ...SERIES_OPTS,
                        ..._self.seriesOpts,
                        data: [],
                    };
                    for (let val of this.dataList) {
                        let categories = val.name;
                        if (val.textColor) {
                            categories = {
                                value: val.name,
                                color: val.textColor,
                            }
                        }
                        Column.categories.push(categories)
                        if (typeof val.num === "number") {
                            let seriesItem = val.num
                            if (val.color) {
                                seriesItem = {
                                    data: val.num,
                                    color: val.color,
                                }
                            }
                            seriesNumArr.push(val.num);
                            seriesData.data.push(seriesItem)
                        } else if (Array.isArray(val.num)) {
                            for (let v of val.num) {

                            }
                        }
                        // ...SERIES_OPTS,
                    }
                    Column.series.push(seriesData)
                } else if (!isEmptyObject(this.dataList, true)) {
                    const series = this.dataList.series || [];
                    for (let [index, value] of new Map(series.map((item, i) => [i, item]))) {
                        let obj = {
                            ...SERIES_OPTS,
                            ..._self.seriesOpts,
                            ...value,
                            show: typeof value.active === "boolean" ? value.active : true
                        }
                        if (value.rgba) obj.color = _self.$util.colorRGBtoHex(value.rgba);
                        if (value.active) {
                            seriesNumArr = seriesNumArr.concat(value.data)
                        }
                        Column.series.push(obj);
                        Column.categories = this.dataList.categories;
                    }
                }
                this.maxSeries = this.getMaxSeries(seriesNumArr);
                Column.opts = await this.getOpts();
                this.setExtra(Column.opts) // 设置扩展配置
                this.setAxis(Column.opts) // 设置坐标轴配置
                return Column;
            },
            // 获取饼状图数据
            async getPieData () {
                const _self = this;
                const {number_format} = _self.$util;
                const {isEmpty, isEmptyObject} = _self.$util.jude;
                //下面这个根据需要保存后台数据，我是为了模拟更新柱状图，所以存下来了
                let Column = {categories: null, series: []};
                for (let val of this.dataList) {
                    let series = isEmptyObject(this.series, true) ? {} : this.series;
                    const obj = {
                        ...SERIES_OPTS,
                        ...series,
                        name: val.name,
                        data: val.num,
                        color: isEmpty(val.color) ? '' : val.color,
                        fontSize: isEmpty(val.fontSize) ? 10 : val.fontSize,
                        format: typeof series.format === "function" ? series.format : function (a) {
                            return `${val.name} ${parseFloat(number_format(a * 100))}%`;
                        }
                    }
                    Column.series.push(obj)
                }
                Column.opts = await this.getOpts();
                this.setExtra(Column.opts) // 设置扩展配置
                Column.opts.disablePieStroke = true;
                return Column;
            },
            // 线图
            async getLineData () {
                const _self = this;
                const {isEmpty, isEmptyObject} = this.$util.jude;
                //下面这个根据需要保存后台数据，我是为了模拟更新柱状图，所以存下来了
                let Column = {categories: [], series: []};
                let seriesNumArr = [];
                if (this.isSingleTable === true) {
                    let seriesData = {
                        ...SERIES_OPTS,
                        ..._self.seriesOpts,
                        data: [],
                    };
                    for (let val of this.dataList) {
                        let categories = val.name;
                        if (val.textColor) {
                            categories = {
                                value: val.name,
                                color: val.textColor,
                            }
                        }
                        Column.categories.push(categories)

                        if (typeof val.num === "number") {
                            let seriesItem = val.num
                            if (val.color) {
                                seriesItem = {
                                    data: val.num,
                                    color: val.color,
                                }
                            }
                            seriesNumArr.push(val.num);
                            seriesData.data.push(seriesItem)
                        } else if (Array.isArray(val.num)) {
                            for (let v of val.num) {

                            }
                        }
                        // ...SERIES_OPTS,
                    }
                    Column.series.push(seriesData)
                } else if (!isEmptyObject(this.dataList, true)) {
                    const series = this.dataList.series || [];
                    for (let [index, value] of new Map(series.map((item, i) => [i, item]))) {
                        let obj = {
                            ...SERIES_OPTS,
                            ..._self.seriesOpts,
                            ...value,
                            show: typeof value.active === "boolean" ? value.active : true
                        }
                        if (value.rgba) {
                            obj.color = _self.$util.colorRGBtoHex(value.rgba);
                        }

                        if (_self.seriesOpts) {

                        }
                        if (value.active) {
                            seriesNumArr = seriesNumArr.concat(value.data)
                        }
                        Column.series.push(obj);
                        Column.categories = this.dataList.categories;
                    }
                }
                this.maxSeries = this.getMaxSeries(seriesNumArr);
                Column.opts = await this.getOpts();
                this.setExtra(Column.opts) // 设置扩展配置
                this.setAxis(Column.opts) // 设置坐标轴配置
                if (!this.yAxis[`data.axisLineColor`]) {
                    Column.opts.yAxis[`data.axisLineColor`] = '#fff'
                }
                if (typeof this.opts.dataLabel !== "boolean")
                    Column.opts.dataLabel = false
                if (typeof this.opts.dataPointShape !== "boolean")
                    Column.opts.dataPointShape = true
                return Column;
            },
            // 获取y最大值
            getMaxSeries (seriesNumArr) {
                let maxSeries = Math.max.apply(null, seriesNumArr)
                if (maxSeries > 10) {
                    let num = 10;
                    while (maxSeries / num > 10) {
                        num *= 10;
                    }
                    return maxSeries - maxSeries % num + num;
                }
                return 10;
            },
            handleCanvasComplete () {
                const _self = this;
                uni.canvasToTempFilePath({
                    x: 0,
                    y: 0,
                    canvasId: _self.canvasId,
                    success: function (res) {
                        // console.warn('+++++++++++++++++++tempFilePath++++++++++++++++++');
                        _self.shareImg = res.tempFilePath;
                    },
                    fail: function (res) {
                        console.warn(res);
                        console.warn('+++++++++++++++++++tempFilePath-error++++++++++++++++++');
                    }
                }, _self)
            },
            handleTouchStart (e) {
                this.canvasColumn.showToolTip(e, {
                    format: function (item, category) {
                        if (typeof item.data === 'object') {
                            return category + ' ' + item.name + ':' + item.data.value
                        } else {
                            return category + ' ' + item.name + ':' + item.data
                        }
                    }
                });
            },
            handleTapImage () {
                let vm = this;
                vm.isHide = false;
                Timer && clearTimeout(Timer);
                Timer = setTimeout(function () {
                    vm.isHide = true;
                }, 1000)
            },

            showChart: async function (n) {
                const _self = this;
                const object2style = this.$util.object2style;
                const canvasId = this.canvasId;
                let chartData = null;
                switch (this.type) {
                    case "column":
                        chartData = await this.getColumnData();
                        break;
                    case "line":
                        chartData = await this.getLineData();
                        break;
                    case "pie": // 圆环
                    case "ring": // 饼图
                        chartData = await this.getPieData();
                        break;
                    case "rose":
                        break;
                    default:
                        return;
                }

                _self.canvasStyle = object2style({
                    height: chartData.opts.height + 'px',
                    width: chartData.opts.width + 'px',
                })

                const data = {
                    ...chartData.opts,
                    categories: chartData.categories,
                    series: chartData.series,
                }
                // console.log(data, `${this.type}配置参数`, _self.canvasColumn);
                if (_self.canvasColumn) {
                    return _self.canvasColumn.updateData(data);
                }
                data.$this = _self;
                data.canvasId = canvasId;
                _self.canvasColumn = new uCharts(data);
                _self.canvasColumn.addEventListener("renderComplete", function (e) {
                    // console.log("renderComplete");
                    _self.handleCanvasComplete();
                })
            },
            updateData () {
                this.showChart();
            },
            // updateData: debounce(function (n) {
            //     this.showChart();
            // }, 0),
        }
    }
</script>

<style scoped lang="scss">
    .azm-chart-column-components {
        width: 100%;
        height: 100%;

        .azm-chart-img {
            width: 100%;
            height: auto;
            display: none;
        }

        .hide-canvas {
            overflow: hidden;

            .azm-chart-img {
                display: block;
            }

            .charts {
                position: absolute;
                top: -10000*2rpx;
            }
        }

        .charts {
            width: 100%;
            height: 100%;
            background-color: #FFFFFF;
        }
    }
</style>
